import 'react-native-get-random-values';

import Storage from './Storage';
import EventSourceImpl from './EventSourceImpl';
import NetworkListener from './NetworkListener';
import version from './version';

import { InstantReactAbstractDatabase } from '@instantdb/react-common';

import {
  i,
  id,
  tx,
  lookup,

  // error
  InstantAPIError,

  // sync table enums
  SyncTableCallbackEventType,

  // types
  type RoomSchemaShape,
  type InstantQuery,
  type InstantQueryResult,
  type InstantSchema,
  type InstantSchemaDatabase,
  type ConnectionStatus,
  type BackwardsCompatibleSchema,
  type IInstantDatabase,
  type Config,
  type Query,
  type QueryResponse,
  type InstantObject,
  type AuthState,
  type User,

  // presence types
  type PresencePeer,

  // schema types
  type AttrsDefs,
  type CardinalityKind,
  type DataAttrDef,
  type EntitiesDef,
  type EntitiesWithLinks,
  type EntityDef,
  type InstantGraph,
  type InstantUnknownSchemaDef,
  type LinkAttrDef,
  type LinkDef,
  type LinksDef,
  type ResolveAttrs,
  type ValueTypes,
  type InstantEntity,
  type ConfigWithSchema,
  type InstaQLEntity,
  type InstaQLResult,
  type InstaQLEntitySubquery,
  type RoomsOf,
  type RoomsDef,
  type PresenceOf,
  type TopicsOf,
  type TopicOf,
  type RoomHandle,
  type CreateParams,
  type InstantConfig,
  type InstantSchemaDef,
  type InstantUnknownSchema,
  type TransactionChunk,
  type InstantRules,
  type UpdateParams,
  type LinkParams,
  type ValidQuery,
  type ExchangeCodeForTokenParams,
  type SendMagicCodeParams,
  type SendMagicCodeResponse,
  type SignInWithIdTokenParams,
  type VerifyMagicCodeParams,
  type VerifyResponse,

  // storage types
  type FileOpts,
  type UploadFileResponse,
  type DeleteFileResponse,

  // sync table types
  type SyncTableCallback,
  type SyncTableCallbackEvent,
  type SyncTableInitialSyncBatch,
  type SyncTableInitialSyncComplete,
  type SyncTableSyncTransaction,
  type SyncTableLoadFromStorage,
  type SyncTableSetupError,
} from '@instantdb/core';

/**
 *
 * The first step: init your application!
 *
 * Visit https://instantdb.com/dash to get your `appId` :)
 *
 * @example
 *  import { init } from "@instantdb/react-native"
 *
 *  const db = init({ appId: "my-app-id" })
 *
 *  // You can also provide a schema for type safety and editor autocomplete!
 *
 *  import { init } from "@instantdb/react-native"
 *  import schema from ""../instant.schema.ts";
 *
 *  const db = init({ appId: "my-app-id", schema })
 *
 *  // To learn more: https://instantdb.com/docs/modeling-data
 */
function init<
  Schema extends InstantSchemaDef<any, any, any> = InstantUnknownSchema,
  UseDates extends boolean = false,
>(
  // Allows config with missing `useDateObjects`, but keeps `UseDates`
  // as a non-nullable in the InstantConfig type.
  config: Omit<InstantConfig<Schema, UseDates>, 'useDateObjects'> & {
    useDateObjects?: UseDates;
  },
): InstantReactNativeDatabase<
  Schema,
  UseDates,
  InstantConfig<Schema, UseDates>
> {
  const configStrict = {
    ...config,
    useDateObjects: (config.useDateObjects ?? false) as UseDates,
  };
  return new InstantReactNativeDatabase<
    Schema,
    UseDates,
    InstantConfig<Schema, UseDates>
  >(configStrict, {
    '@instantdb/react': version,
  });
}

/**
 * @deprecated
 * `init_experimental` is deprecated. You can replace it with `init`.
 *
 * @example
 *
 * // Before
 * import { init_experimental } from "@instantdb/react-native"
 * const db = init_experimental({  ...  });
 *
 * // After
 * import { init } from "@instantdb/react-native"
 * const db = init({ ...  });
 */
const init_experimental = init;

class InstantReactNativeDatabase<
  Schema extends InstantSchemaDef<any, any, any>,
  UseDates extends boolean,
  Config extends InstantConfig<Schema, UseDates> = InstantConfig<
    Schema,
    UseDates
  >,
> extends InstantReactAbstractDatabase<Schema, UseDates, Config> {
  static Storage = Storage;
  static NetworkListener = NetworkListener;
  static EventSourceImpl = EventSourceImpl;
}

export {
  init,
  init_experimental,
  id,
  tx,
  lookup,
  i,
  InstantReactNativeDatabase,

  // error
  InstantAPIError,

  // sync table enums
  SyncTableCallbackEventType,

  // types
  type Config,
  type Query,
  type QueryResponse,
  type InstantObject,
  type User,
  type AuthState,
  type ConnectionStatus,
  type InstantQuery,
  type InstantQueryResult,
  type InstantSchema,
  type InstantSchemaDatabase,
  type IInstantDatabase,
  type InstantEntity,
  type RoomSchemaShape,

  // presence types
  type PresencePeer,

  // schema types
  type AttrsDefs,
  type CardinalityKind,
  type DataAttrDef,
  type EntitiesDef,
  type EntitiesWithLinks,
  type EntityDef,
  type InstantGraph,
  type CreateParams,
  type LinkAttrDef,
  type InstantConfig,
  type LinkDef,
  type InstantUnknownSchemaDef,
  type LinksDef,
  type RoomsOf,
  type RoomsDef,
  type RoomHandle,
  type PresenceOf,
  type TopicsOf,
  type TopicOf,
  type ResolveAttrs,
  type ValueTypes,
  type InstaQLEntity,
  type InstaQLResult,
  type InstaQLEntitySubquery,
  type InstantSchemaDef,
  type InstantUnknownSchema,
  type BackwardsCompatibleSchema,
  type InstantRules,
  type UpdateParams,
  type LinkParams,
  type ValidQuery,
  type ExchangeCodeForTokenParams,
  type SendMagicCodeParams,
  type TransactionChunk,
  type SendMagicCodeResponse,
  type SignInWithIdTokenParams,
  type VerifyMagicCodeParams,
  type VerifyResponse,

  // storage types
  type FileOpts,
  type UploadFileResponse,
  type DeleteFileResponse,

  // sync table types
  type SyncTableCallback,
  type SyncTableCallbackEvent,
  type SyncTableInitialSyncBatch,
  type SyncTableInitialSyncComplete,
  type SyncTableSyncTransaction,
  type SyncTableLoadFromStorage,
  type SyncTableSetupError,
};
